package offical.functionLambda

open class A {
    //函数参数可以有默认值，当省略相应的参数时使用默认值。这可以减少重载数量
    open fun to(params: Int = 1) {
    }
}

class B : A() {
    //覆盖方法总是使用与基类型方法相同的默认参数值。 当覆盖一个带有默认参数值的方法时，必须从签名中省略默认参数值
    override fun to(params: Int) {
    }

    fun beforeDefaultParams(params1: Int = 0, params2: Int) {
    }

    fun lambdaAfter(params1: Int = 1, params2: Int = 3, lambdaParmas: () -> Unit) {

    }

}

//单表达式函数 ,自动类型推倒。
fun double(x: Int) = x * 2

/**
 * 将可变参数转换为集合
 * 可变数量的参数（Varargs）函数的参数（通常是最后一个）可以用 vararg 修饰符标记
 */
fun <T> asList(vararg ts: T, number: Number): List<T> {
    val list = ArrayList<T>()
    for (t in ts) {
        list.add(t)
    }
    return list
}


/* 中缀表达式
标有 infix 关键字的函数也可以使用中缀表示法（忽略该调用的点与圆括号）调用
 * 它们必须是成员函数或扩展函数；它们必须只有一个参数；其参数不得接受可变数量的参数且不能有默认值。
  * */

infix fun Array<String>.searchWithIndex(str: String): Int {
    for (element in this.withIndex()) {
        if (element.value == str) {
            return element.index
        }
    }
    return -1
}

/**
 * 中缀函数调用的优先级低于算术操作符、类型转换以及 rangeTo 操作符。
 * 中缀函数调用的优先级高于布尔操作符 && 与 ||、is- 与 in- 检测以及其他一些操作符
 */
class InfixClass {

    infix fun add(str: String) {

    }

    /**
     * 当使用中缀表示法在当前接收者上调用方法时，需要显式使用 this；不能像常规方法调用那样省略。
     */
    fun build() {
        this add "66"
        add("88")
    }
}

/*局部函数*/
fun outFun() {
    //外部局部变量
    val outer = 66

    //局部函数可以访问外部函数（即闭包）的局部变量
    fun innnerFun() {
        val inner = outer + 22
    }

}


fun main(args: Array<String>) {
    //如果一个默认参数在一个无默认值的参数之前，那么该默认值只能通过使用命名参数调用该函数来使用
    val b = B()

    b.beforeDefaultParams(params2 = 2)

//    如果最后一个 others 表达式参数从括号外传给函数函数调用，那么允许默认参数不传值
    b.lambdaAfter { }//params1: Int = 1, params2: Int = 3

    b.lambdaAfter(100) {}//params1: Int = 100, params2: Int = 3

    b.lambdaAfter(lambdaParmas = {})

    val array = arrayOf(1, 2, 3)
    //使用伸展（spread）操作符（在数组前面加 *）
    asList(-1, 0, *array, 4, 5, number = 3).also(::println)

    (arrayOf("6", "7", "3", "7", "2") searchWithIndex "3").also(::println)
}